package com.todo.user.infrastructure.repository.impl;

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONObject;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.enums.ResultTypeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.common.utils.MathUtils;
import com.todo.common.utils.StringUtils;
import com.todo.common.utils.TodoCommonUtils;
import com.todo.user.common.enums.UserOperateTypeEnum;
import com.todo.user.infrastructure.convert.UserAccountConvert;
import com.todo.user.infrastructure.entity.condition.UserAccountCondition;
import com.todo.user.infrastructure.entity.domain.UserAccountDO;
import com.todo.user.infrastructure.entity.po.UserAccountPO;
import com.todo.user.infrastructure.entity.po.UserOperateRecordPO;
import com.todo.user.infrastructure.entity.po.UserTravelInfoPO;
import com.todo.user.infrastructure.mapper.UserAccountMapper;
import com.todo.user.infrastructure.mapper.UserTravelInfoMapper;
import com.todo.user.infrastructure.repository.UserAccountRepository;
import com.todo.user.infrastructure.repository.UserOperateRecordRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * (UserAccount)表服务实现类
 *
 * @author zhangwenxiang
 * @since 2024-03-04 21:10:04
 */
@Slf4j
@Repository("userAccountRepository")
public class UserAccountRepositoryImpl implements UserAccountRepository {
    @Resource
    private UserAccountMapper userAccountMapper;
    @Resource
    private UserTravelInfoMapper userTravelInfoMapper;
    @Resource
    private UserOperateRecordRepository userOperateRecordRepository;


    @Override
    public PageResult<UserAccountPO> queryUserAccountPOByCondition(UserAccountCondition userAccountCondition) {
        PageResult<UserAccountPO> pageResult = new PageResult<>();
        if (userAccountCondition == null) {
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        pageResult.setPageNum(userAccountCondition.getPageIndex());
        pageResult.setPageSize(userAccountCondition.getPageSize());
        long count = queryCountByCondition(userAccountCondition);
        if (count <= 0) {
            return pageResult;
        }
        pageResult.setPageCount((int) MathUtils.divide(count, userAccountCondition.getPageSize()));
        pageResult.setTotal(count);
        List<UserAccountPO> userAccountPOList = userAccountMapper.queryUserAccountByCondition(userAccountCondition);
        if (CollectionUtils.isEmpty(userAccountPOList)) {
            pageResult.setHasNext(false);
            return pageResult;
        }
        pageResult.setResults(userAccountPOList);
        pageResult.setCurrentIndex(userAccountPOList.get(0).getId());
        pageResult.setHasNext(userAccountPOList.size() >= userAccountCondition.getPageSize());
        return pageResult;
    }

    @Override
    public Long queryCountByCondition(UserAccountCondition userAccountCondition) {
        if (userAccountCondition == null || userAccountCondition.getPageSize() <= 0) {
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        return userAccountMapper.queryCountByCondition(userAccountCondition);
    }

    @Override
    public UserAccountPO queryUserAccountPOById(Long id) {
        if (id == null || id < 0) {
            return null;
        }
        return userAccountMapper.queryUserAccountPOById(id);
    }

    @Override
    public UserAccountDO queryUserInfoById(Long id) {
        UserAccountPO userAccountPO = queryUserAccountPOById(id);
        if (userAccountPO == null) {
            return null;
        }
        UserTravelInfoPO userTravelInfoPO = userTravelInfoMapper.queryUserTravelInfoPOById(id);
        UserAccountDO userAccountDO = UserAccountConvert.convertToUserAccountDO(userAccountPO, userTravelInfoPO);
        return userAccountDO;
    }

    @Override
    public Boolean insertUserAccountPO(UserAccountPO userAccountPO) {
        if (userAccountPO == null) {
            return false;
        }
        try {
            if (!baseFieldCheck(userAccountPO)) {
                return false;
            }
            int insertResult = userAccountMapper.insertUserAccountPO(userAccountPO);
            if (insertResult > 0) {
                operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.REGISTER, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.SUCCESS);
            } else {
                operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.REGISTER, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.FAILED);
            }
            return insertResult > 0;
        } catch (Exception ex) {
            log.error("UserAccountRepository#insertUserAccountPO 新增用户账户信息异常 userAccountPO：【{}】", JSONObject.toJSONString(userAccountPO), ex);
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.REGISTER, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.ERROR);
        }
        return false;
    }

    @Override
    public Boolean updateUserAccountPOById(UserAccountPO userAccountPO) {
        if (userAccountPO == null || userAccountPO.getId() == null) {
            return false;
        }
        UserAccountPO alreadyUserAccountPO = queryUserAccountPOById(userAccountPO.getId());
        if (alreadyUserAccountPO == null) {
            log.warn("UserAccountRepository#updateUserAccountPOById 更新用户账户信息失败，用户信息为空 userAccountPO：【{}】", JSONObject.toJSONString(userAccountPO));
            return false;
        }
        try {
            if (!baseFieldCheck(userAccountPO)) {
                return false;
            }
            int updateResult = userAccountMapper.updateUserAccountPOById(userAccountPO);
            if (updateResult > 0) {
                operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.UPDATE, JSONObject.toJSONString(alreadyUserAccountPO), JSONObject.toJSONString(userAccountPO), ResultTypeEnum.SUCCESS);
            } else {
                operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.UPDATE, JSONObject.toJSONString(alreadyUserAccountPO), JSONObject.toJSONString(userAccountPO), ResultTypeEnum.FAILED);
            }
            return updateResult > 0;
        } catch (Exception ex) {
            log.error("UserAccountRepository#updateUserAccountPOById 更新用户账户信息异常 userAccountPO：【{}】", JSONObject.toJSONString(userAccountPO), ex);
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.UPDATE, JSONObject.toJSONString(alreadyUserAccountPO), JSONObject.toJSONString(userAccountPO), ResultTypeEnum.ERROR);
        }
        return false;
    }

    @Override
    @Transactional
    public Boolean updateUserAccountById(UserAccountDO userAccountDO) {
        if (userAccountDO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        UserAccountPO userAccountPO = UserAccountConvert.buildUserAccountPO(userAccountDO);
        Boolean accountResult = updateUserAccountPOById(userAccountPO);
        if (!accountResult) {
            log.warn("UserAccountRepository#updateUserAccountById 更新账户信息失败，更新详情信息失败 userAccountPO：【{}】", JSONObject.toJSONString(userAccountPO));
            return false;
        }
        UserTravelInfoPO userTravelInfoPO = UserAccountConvert.buildUserTravelInfoPO(userAccountDO);
        if (userTravelInfoPO == null) {
            log.info("UserAccountRepository#updateUserAccountById 更新账户信息完成，旅游详情信息为空，默认不操作 userAccountDO：【{}】", JSONObject.toJSONString(userAccountDO));
            return true;
        }
        UserTravelInfoPO alreadyUserTravelInfoPO = userTravelInfoMapper.queryUserTravelInfoPOById(userAccountDO.getId());
        if (alreadyUserTravelInfoPO == null) {
            Boolean insertResult = insertUserTravelInfoPO(userTravelInfoPO);
            if (!insertResult) {
                log.warn("UserAccountRepository#updateUserAccountById 更新账户信息失败，不存在旅游信息新增失败 userTravelInfoPO：【{}】", JSONObject.toJSONString(userTravelInfoPO));
                throw new BizException(BizErrorCodeEnum.SYSTEM_ERROR);
            }
            return true;
        }
        int travelResult = userTravelInfoMapper.updateUserTravelInfoPOById(userTravelInfoPO);
        if (travelResult == 0) {
            log.warn("UserAccountRepository#updateUserAccountById 更新账户信息失败，旅游信息更新失败 userTravelInfoPO：【{}】", JSONObject.toJSONString(userTravelInfoPO));
            throw new BizException(BizErrorCodeEnum.SYSTEM_ERROR);
        }
        return true;
    }


    @Override
    public Boolean removeUserAccountPOById(Long id) {
        if (id == null || id < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        UserAccountPO userAccountPO = queryUserAccountPOById(id);
        if (userAccountPO == null) {
            log.info("UserAccountRepository#removeUserAccountPOById 删除账户信息完成，根据id查询账户为空，默认操作成功 id：【{}】", id);
            return true;
        }
        int accountResult = userAccountMapper.removeUserAccountPOById(id);
        if (accountResult > 0) {
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.LOG_OFF, JSONObject.toJSONString(userAccountPO), null, ResultTypeEnum.SUCCESS);
        } else {
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.LOG_OFF, JSONObject.toJSONString(userAccountPO), null, ResultTypeEnum.FAILED);
        }
        return accountResult != 0;
    }

    private boolean baseFieldCheck(UserAccountPO userAccountPO) {
        if (userAccountPO == null) {
            return false;
        }
        //判断字符长度
        return true;
    }

    @Override
    public Boolean insertUserTravelInfoPO(UserTravelInfoPO userTravelInfoPO) {
        if (userTravelInfoPO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        return userTravelInfoMapper.insertUserTravelInfoPO(userTravelInfoPO) > 0;
    }

    @Override
    public UserAccountPO queryUserAccountPOByUserName(String userName) {
        if (StringUtils.isBlank(userName)) {
            return null;
        }
        return userAccountMapper.queryUserAccountPOByUserName(userName);
    }

    @Override
    public UserAccountPO queryUserAccountPOByPhone(String phone) {
        if (StringUtils.isEmpty(phone)) {
            return null;
        }
        return userAccountMapper.queryUserAccountPOByPhone(phone);
    }

    @Override
    public Boolean updateUserSecret(Long userId, String newPassword) {
        if (userId == null || userId < 0 || StringUtils.isEmpty(newPassword)) {
            return false;
        }
        UserAccountPO userAccountPO = new UserAccountPO();
        userAccountPO.setId(userId);
        userAccountPO.setPassword(newPassword);
        int updateResult = userAccountMapper.updateUserAccountPOById(userAccountPO);
        if (updateResult > 0) {
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.TRANSFER_PASSWORD, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.SUCCESS);
        } else {
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.TRANSFER_PASSWORD, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.FAILED);
        }
        return updateResult > 0;
    }

    @Override
    public Boolean updateUserStatusById(Long userId, int status, String reason) {
        if (userId == null || userId < 0) {
            return false;
        }
        UserAccountPO userAccountPO = new UserAccountPO();
        userAccountPO.setId(userId);
        userAccountPO.setStatus(status);
        int updateResult = userAccountMapper.updateUserAccountPOById(userAccountPO);
        if (updateResult > 0) {
            operateLogRecord(userAccountPO.getId(), UserOperateTypeEnum.ADMIN_OPERATE, null, JSONObject.toJSONString(userAccountPO), ResultTypeEnum.SUCCESS);
        }
        log.info("UserAccountRepository#updateUserStatusById更新用户状态完成 用户Id：{},更新后状态：{},原因：{}" ,userId, status, reason);
        return updateResult > 0;
    }

    @Override
    public List<UserAccountDO> queryUserInfoByIdList(List<Long> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return Collections.emptyList();
        }
        List<UserAccountPO> userAccountPOList = userAccountMapper.queryUserAccountByIdList(userIdList);
        List<UserTravelInfoPO> userTravelInfoPOList = userTravelInfoMapper.queryUserTravelInfoByIdList(userIdList);
        if (CollectionUtils.isEmpty(userAccountPOList)) {
            return Collections.emptyList();
        }
        //构建旅游备注信息map，用户后续筛选
        Map<Long, UserTravelInfoPO> userTravelInfoPOMap = new HashMap<>();
        if (CollectionUtils.isEmpty(userTravelInfoPOList)) {
            userTravelInfoPOMap = userTravelInfoPOList
                    .stream()
                    .collect(Collectors.toMap(UserTravelInfoPO::getId, Function.identity()));
        }
        List<UserAccountDO> userAccountDOList = new ArrayList<>();
        for (UserAccountPO userAccountPO : userAccountPOList) {
            UserAccountDO userAccountDO = UserAccountConvert.convertToUserAccountDO(userAccountPO, userTravelInfoPOMap.get(userAccountPO.getId()));
            userAccountDOList.add(userAccountDO);
        }
        return userAccountDOList;
    }

    /**
     * 操作日志
     *
     * @param userId
     * @param operateTypeEnum
     * @param origin
     * @param after
     * @param result
     */
    private void operateLogRecord(Long userId, UserOperateTypeEnum operateTypeEnum, String origin, String after, ResultTypeEnum result) {
        ThreadUtil.execAsync(() -> {
            UserOperateRecordPO operateRecordPO = new UserOperateRecordPO();
            operateRecordPO.setUserId(userId);
            operateRecordPO.setOperateType(operateTypeEnum.getType());
            operateRecordPO.setOriginInfo(origin == null ? "" : origin);
            operateRecordPO.setAfterInfo(after == null ? "" : after);
            operateRecordPO.setOperateResult(result.getType());
            operateRecordPO.setIsDelete(0);
            operateRecordPO.setId(TodoCommonUtils.buildLongGuid());
            Date currentDate = new Date();
            operateRecordPO.setCreateTime(currentDate);
            operateRecordPO.setUpdateTime(currentDate);
            userOperateRecordRepository.insertUserOperateRecordPO(operateRecordPO);
        });
    }

}
